/*
**    Copyright (C) 2003-2011 Institute for Systems Biology
**                            Seattle, Washington, USA.
**
**    This library is free software; you can redistribute it and/or
**    modify it under the terms of the GNU Lesser General Public
**    License as published by the Free Software Foundation; either
**    version 2.1 of the License, or (at your option) any later version.
**
**    This library is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**    Lesser General Public License for more details.
**
**    You should have received a copy of the GNU Lesser General Public
**    License along with this library; if not, write to the Free Software
**    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*/

package org.systemsbiology.tsv;

import org.systemsbiology.util.CloneableGeneric;

import java.io.Externalizable;
import java.io.Serializable;

/**
 * Basic implementer of {@link Field}, using cloned data of the supplied type. Hashable.
 *
 *  Allows for cloned data storage into and out of a {@link Field} object. Unlike {@link BasicField}, this
 *  representation makes no assumptions about reference integrity of the original object beyond the point of original
 *  passage. The cost of this double the memory footprint, as each instance of BasicClonedField explicitly copies the
 *  contents of the passed object into itself via our genericized {@link CloneableGeneric}.
 *
 *  If immutability of the contained data structure is desired, consider maintaining this constraint in your
 *  implementation of generic T.
 * @author trobinso
 */
public class BasicClonedField
        <T extends Serializable & CloneableGeneric<T> & Comparable<T> & Cloneable> implements Field<T> {
    private static final long serialVersionUID = -1638139954370568459L;

    T contents = null;

    /**
     * Default constructor for BasicClonedField
     */
    public BasicClonedField() {}

    /**
     * Constructor for BasicClonedField, requiring contents to be immediately supplied
     * @param contents T immediate contents for this Field
     */

    public BasicClonedField(T contents) {
        this.setContents(contents);
    }

    /**
     * @inheritDoc
     */
    public void setContents(T contents) {
        assert(contents != null);

        try {
            this.contents = contents.cloneMe();
        } catch (CloneNotSupportedException e) {
            // Gives this method the ability to crash our program. To be fair, we'd like it to.
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * @inheritDoc
     */
    public T getContents() {
        assert(contents != null);

        try {
            return contents.cloneMe();
        } catch (CloneNotSupportedException e) {
            // Gives this method the ability to crash our program. To be fair, we'd like it to.
            throw new IllegalStateException(e);
        }
    }

    public int compareTo(Field<T> f) {
        assert(this.contents != null);

        return this.contents.compareTo(f.getContents()); // Note: requires consistency with equals to behave correctly
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        BasicClonedField that = (BasicClonedField) o;

        if (contents != null ? !contents.equals(that.contents) : that.contents != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return contents != null ? contents.hashCode() : 0;
    }

    @Override
    public String toString() {
        return "BasicClonedField{\"" + contents + "\"}";
    }
}
